package nio.buffer;

import org.junit.Test;

import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @program JavaBase
 * @description: 缓冲区
 * @author: zhanglu
 * @create: 2019-06-15 06:35:00
 *
 * 1、缓冲区(Buffer): 在java nio 中负责数据额度存取，
 *    缓冲区就是数组，用于存储不同数据类型的数据
 *    根据数据类型不同(boolean除外)，提供了相应类型的缓冲区
 *
 * ByteBuffer
 * CharBuffer
 * ShortBuffer
 * IntBuffer
 * LongBuffer
 * FloatBuffer
 * DoubleBuffer
 *
 * 上述缓冲区的管理方式几乎一致，通过 allocate()获取缓冲区
 *
 * 2、缓冲区存取数据的两个核心方法：
 *    - put(): 存入数据到缓冲区中
 *    - get(): 获取缓冲区中的数据
 *
 * 3、缓冲区中的四个核心的属性
 *    - capacity: 容量，标识缓冲区中最大存储数据的容量，一旦声明不能改变
 *    - limit: 界限，标识缓冲区中可以操作数据的大小，limit后数据不能进行读写
 *    - position: 位置，标识缓冲区中正在操作数据的位置
 *    - mark: 标记，标识记录当前position的位置，可以通过reset恢复到mark的位置
 *
 *    0 <= mark <= position <= limit <= capacity
 *
 * 4、直接缓冲区与非直接缓冲区
 *    - 非直接缓冲区：通过allocate方法分配非直接缓冲区，将缓冲区建立在JVM的内存中
 *    - 直接缓冲区：通过allocateDirect方法非配直接缓冲区，将缓冲区建立在无力内存中，可以提高效率
 *
 */
public class TestBuffer01 {


    @Test
    public void test01(){
        String str = "abcde";

        //1、分配一个指定大小的缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);

        System.out.println("==============allocate==============");
        System.out.println(buf.position() + "=" + buf.limit() + "=" + buf.capacity());

        //2、存入数据到缓冲区中，limit变   中文三个字节？
        buf.put(str.getBytes());

        System.out.println("==============put==============");
        System.out.println(buf.position() + "=" + buf.limit() + "=" + buf.capacity());

        //3、切换到读数据模式，position 置为0
        buf.flip();
        System.out.println("==============flip==============");
        System.out.println(buf.position() + "=" + buf.limit() + "=" + buf.capacity());

        //4、读取缓冲区的数据,position也会变动
        byte[] dst = new byte[buf.limit()];
        buf.get(dst);
        System.out.println("==============get==============");
        System.out.println(new String(dst, 0, dst.length));
        System.out.println(buf.position() + "=" + buf.limit() + "=" + buf.capacity());

        //5、可重复读，position回到起点
        buf.rewind();
        System.out.println("==============rewind==============");
        System.out.println(buf.position() + "=" + buf.limit() + "=" + buf.capacity());

        //6、清空缓冲区，实际上是容量位置初始化，但是缓中区中的数据依然还在，处于被'遗忘'状态
        buf.clear();
        System.out.println("==============clear==============");
        System.out.println(buf.position() + "=" + buf.limit() + "=" + buf.capacity());

        System.out.println((char)buf.get());

    }
    
    @Test
    public void test02(){
        String str = "abcde";
        ByteBuffer buf = ByteBuffer.allocate(1024);

        buf.put(str.getBytes());
        System.out.println("==============put==============");
        System.out.println(buf.position() + "=" + buf.limit() + "=" + buf.capacity());


        buf.flip();
        System.out.println("==============flip==============");
        System.out.println(buf.position() + "=" + buf.limit() + "=" + buf.capacity());


        byte[] dst = new byte[buf.limit()];
        buf.get(dst, 0, 2);

        System.out.println(new String(dst, 0 , 2));
        System.out.println("==============get==============");
        System.out.println(buf.position() + "=" + buf.limit() + "=" + buf.capacity());

        //mark 标记
        buf.mark();
        System.out.println("==============mark==============");
        System.out.println(buf.position() + "=" + buf.limit() + "=" + buf.capacity());


        buf.get(dst, 2, 2);

        System.out.println(new String(dst, 2 , 2));
        System.out.println("==============get==============");
        System.out.println(buf.position() + "=" + buf.limit() + "=" + buf.capacity());

        //恢复到mark标记的位置
        buf.reset();
        System.out.println("==============reset==============");
        System.out.println(buf.position() + "=" + buf.limit() + "=" + buf.capacity());

        if(buf.hasRemaining()){ //缓冲区中是否还有剩余数据
            //获取缓冲区可以操作的数量
            System.out.println(buf.remaining());
        }

    }

    /**
     * 直接缓冲区
     */
    @Test
    public void test03(){
        //直接缓冲区
        ByteBuffer buf1 = ByteBuffer.allocateDirect(1024);

        System.out.println(buf1.isDirect());

        ByteBuffer buf2 = ByteBuffer.allocate(1024);

        System.out.println(buf2.isDirect());

    }

    @Test
    public void test04() throws Exception {
//        CompletableFuture<String> completableFuture
//                = CompletableFuture.supplyAsync(() -> "Hello");
//        CompletableFuture<Void> future = completableFuture
//                .thenRun(() -> {
//                    try {
//                        TimeUnit.SECONDS.sleep(2);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                    System.out.println("Computation finished.");
//                });
//
//        Void aVoid = future.get();
//
//
//        CompletableFuture<String> completableFuture2
//                = CompletableFuture.supplyAsync(() -> "Hello");
//
//        CompletableFuture<Void> future2 = completableFuture
//                .thenAccept(s -> {
//                    System.out.println("Computation returned: " + s);
//                });
//        future2.get();

//        String s = "000";
//        CompletableFuture.runAsync(() -> System.out.println(111 + s)).thenAccept((s1) -> System.out.println(s1));
//        CompletableFuture.supplyAsync(() -> {
//            System.out.println(111 + s);
//            return 111+s;
//        }).thenAccept((s1) -> System.out.println(s1));
//
//        CompletableFuture.supplyAsync(() -> {
//            System.out.println(111 + s);
//            return 111+s;
//        }).thenRun(() -> System.out.println(222));
//
//        String s2 = CompletableFuture.supplyAsync(() -> {
//            System.out.println(111 + s);
//            return 111 + s;
//        }).thenApply((s1) -> {
//            System.out.println(s1);
//            return s1;
//        }).get();
//
//        System.out.println(s2);

//        CompletableFuture.supplyAsync(() -> {
//            throw new RuntimeException("Computation error!");
//        } ).exceptionally((e) -> {  //异常的话才会执行
//            return String.valueOf(e);
//        }).thenApply((o) -> {
//            return o;
//        });
//
//        String name = null;
//        CompletableFuture<String> completableFuture
//                =  CompletableFuture.supplyAsync(() -> {
//            if (name == null) {
//                throw new RuntimeException("Computation error!");
//            }
//            return "Hello, " + name;
//        }).handle((s, t) -> {
//            return s != null ? s : "Hello, Stranger!";
//        });
//        System.out.println(completableFuture.get());

        CompletableFuture<Integer> applyToEither = CompletableFuture.supplyAsync(() -> {
            int nextInt = new Random().nextInt(10);
            try {
                Thread.sleep(nextInt);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f1=" + nextInt);
            return nextInt;
        }).applyToEither(CompletableFuture.supplyAsync(() -> {
            int nextInt = new Random().nextInt(10);
            try {
                Thread.sleep(nextInt);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f2=" + nextInt);
            return nextInt;
        }), i -> i).thenApply(j -> j + 1);

        System.out.println(applyToEither.get());

    }

    @Test
    public void test05(){
        StringBuilder s = new StringBuilder();
        s.append("1");
        StringBuilder r = s;
        r.append("2");

        System.out.println(s);
        System.out.println(r);
    }

}
